import axios, {
  AxiosInstance,
  AxiosError,
  AxiosResponse,
  InternalAxiosRequestConfig,
  AxiosRequestConfig,
} from 'axios'
import { Resp } from '@/types/resp.ts'
import { ApiError } from '@/error/ApiError.ts'
import { getOrGenerateUUID } from '@/utils/uuid.ts'

// 请求配置接口
interface RequestConfig<T = unknown> extends AxiosRequestConfig {
  // 忽略的状态码，这些状态码不会抛出异常
  ignoreErrorCodes?: number[]
  // 响应数据类型
  data?: T
}

// 请求结果接口
interface RequestResult<T = unknown> {
  success: boolean // 是否成功 (code === 200)
  code: number // 状态码
  message: string // 消息
  data: T // 数据
}

const baseURL = window.location.origin + '/api'

const service: AxiosInstance = axios.create({
  timeout: 5000,
  baseURL: baseURL,
  withCredentials: true,
})

service.interceptors.request.use(
  (config: InternalAxiosRequestConfig) => {
    const uuid = getOrGenerateUUID()
    config.headers.set('X-Visitor-UUID', uuid)
    return config
  },
  (error: AxiosError) => {
    return Promise.reject(error)
  }
)

service.interceptors.response.use(
  (response: AxiosResponse) => {
    if (response.status === 200) {
      return response.data
    } else {
      return Promise.reject()
    }
  },
  (error: AxiosError) => {
    return Promise.reject(error)
  }
)

/**
 * 后端返回状态非200时抛出自定义异常ApiError
 * @param config
 */
const request = async <T = unknown>(config: AxiosRequestConfig): Promise<T> => {
  const res: Resp<T> = await service(config)
  if (res.code !== 200) {
    throw new ApiError(res.code, res.message)
  }
  return res.data
}

/**
 * 静默请求方法，允许指定忽略的状态码
 * @param config 请求配置
 * @param ignoreCodes 要忽略的状态码数组，默认为空
 */
const silentRequest = async <T = unknown>(
  config: AxiosRequestConfig,
  ignoreCodes: number[] = []
): Promise<T> => {
  const res: Resp<T> = await service(config)
  if (res.code !== 200 && !ignoreCodes.includes(res.code)) {
    throw new ApiError(res.code, res.message)
  }
  return res.data
}

/**
 * 配置化的请求方法，支持在请求配置中指定要忽略的状态码
 * @param config 扩展的请求配置
 */
const requestWithConfig = async <T = unknown>(config: RequestConfig<T>): Promise<T> => {
  const { ignoreErrorCodes = [], ...axiosConfig } = config
  const res: Resp<T> = await service(axiosConfig)

  if (res.code !== 200 && !ignoreErrorCodes.includes(res.code)) {
    throw new ApiError(res.code, res.message)
  }
  return res.data
}

/**
 * 返回完整响应信息的请求方法，不抛出异常
 * 适用于需要根据状态码进行业务逻辑判断的场景
 * @param config 请求配置
 */
const requestWithResult = async <T = unknown>(
  config: AxiosRequestConfig
): Promise<RequestResult<T>> => {
  const res: Resp<T> = await service(config)
  return {
    success: res.code === 200,
    code: res.code,
    message: res.message,
    data: res.data,
  }
}

export default request
export { silentRequest, requestWithConfig, requestWithResult }
export type { RequestConfig, RequestResult }
